package com.sinodata.bsm.center.service.resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.sinodata.bsm.center.bean.ResBean;
import com.sinodata.bsm.center.cache.HealthCalcRuleCache;
import com.sinodata.bsm.center.cache.HealthTransRuleCache;
import com.sinodata.bsm.center.cache.ResCache;
import com.sinodata.bsm.center.dao.BaseDao;
import com.sinodata.bsm.center.dao.impl.ResHealthDaoImpl;
import com.sinodata.bsm.center.engine.resource.health.ResHealthEngine;
import com.sinodata.bsm.common.exception.InvalidArgumentException;
import com.sinodata.bsm.common.utils.RandomGUID;
import com.sinodata.bsm.common.vo.HealthCalcRule;
import com.sinodata.bsm.common.vo.HealthStatusHis;
import com.sinodata.bsm.common.vo.HealthTransRule;
import com.sinodata.bsm.common.vo.Res;

@Service
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ResHealthService {
    @Autowired
    private ResCache resCache;
    @Autowired
    private BaseDao baseDao;
    @Autowired
    private HealthTransRuleCache healthTransRuleCache;
    @Autowired
    private HealthCalcRuleCache healthCalcRuleCache;
    @Autowired
    private ResHealthDaoImpl resHealthDaoImpl;

    /**
     * 保存健康度规则
     * @param calRule
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveOrUpdateHealthCalcRule(HealthCalcRule calRule) {
        baseDao.saveOrUpdate(calRule);
        healthCalcRuleCache.put(calRule);
        ResHealthEngine.getInstance().refreshResFromChild(ResBean.get(calRule.getId()).res());
    }

    /**
     * 根据一个资源id找到算法规则
     * @param resId
     * @return
     */
    public HealthCalcRule findByResId(Long resId) {
        return healthCalcRuleCache.get(resId);
    }

    public List<HealthTransRule> findChildHealthTransRule(Long parentResId) {
        return healthTransRuleCache.findChildrenRule(parentResId);
    }

    /**
     * 保存一个父资源下所有直接子资源的传递规则
     * @param calRule
     * @throws InvalidArgumentException 
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveHealthTransRule(Long parentResId, List<HealthTransRule> transList) throws InvalidArgumentException {
        for (HealthTransRule rule : transList) {
            if (rule.getParentResId().longValue() != parentResId) {
                throw new InvalidArgumentException();
            }
            HealthTransRule oldVal = healthTransRuleCache.get(parentResId.longValue(), rule.getChildResId().longValue());
            if (oldVal != null) {
                baseDao.delete(oldVal);
            }
            baseDao.save(rule);
            healthTransRuleCache.put(rule);
        }
        ResHealthEngine.getInstance().refreshResFromChild(ResBean.get(parentResId).res());
    }

    /**
     * 恢复一个父资源的子资源传递规则
     * @param parentResId
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteHealthTransRule(Long parentResId) {
        resHealthDaoImpl.deleteHealthTransRule(parentResId);
        healthTransRuleCache.remove(parentResId);
        ResHealthEngine.getInstance().refreshResFromChild(ResBean.get(parentResId).res());
    }

    /**
     * 新增资源时调用
     * @param res
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void addResHealthStatus(Res res) {
        HealthStatusHis his = new HealthStatusHis();
        his.setId(RandomGUID.getGUID());
        his.setResId(res.getId());
        his.setStartTime(new Date());
        his.setHealthDegree(res.getHealthDegree());
        baseDao.save(his);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void batchAddResHealthStatus(List<Res> resList) throws Exception {
        List<HealthStatusHis> healthStatusHisList = new ArrayList<HealthStatusHis>();
        for (Res res : resList) {
            HealthStatusHis his = new HealthStatusHis();
            his.setId(RandomGUID.getGUID());
            his.setResId(res.getId());
            his.setStartTime(new Date());
            his.setHealthDegree(res.getHealthDegree());
            healthStatusHisList.add(his);
        }
        baseDao.batchSave(healthStatusHisList);
    }

    /**
     * 更新资源健康度状态
     * @param res
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateResHealthStatus(Res res, int[] newstatus) {
        res.setHealthStatus(newstatus[1]);
        res.setHealthDegree(newstatus[0]);
        baseDao.update(res);
        resCache.put(res.getId().longValue(), res);
        Date d = new Date();
        HealthStatusHis his = new HealthStatusHis();
        his.setId(RandomGUID.getGUID());
        his.setResId(res.getId());
        his.setStartTime(d);
        his.setHealthDegree(res.getHealthDegree());
        resHealthDaoImpl.updateResHealthHisEndTime(res.getId(), d);
        baseDao.save(his);

    }

    /**
     * 查询指定时间段内的资源健度度汇聚
     * @param resId
     * @param startTime
     * @param endTime
     * @param type
     * @return
     */
    public List queryResHealthHis(Long resId, String startTime, String endTime, int type) {
        return resHealthDaoImpl.queryResHealthHis(resId, startTime, endTime, type);
    }
}
